package ga.cross;

import ga.GARun;
import ga.individuals.Individual;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import org.apache.log4j.Logger;

public class Anular implements CrossMethod {
	private static final Logger LOGGER = Logger.getLogger(Anular.class);
	private Integer crosspoint;
	private Integer lengthToCross;
	
	public Anular(Integer lenghtToCross) {
		if (lenghtToCross == null || lenghtToCross < 0 || lenghtToCross > GARun.bitsInDouble) {
			LOGGER.error("Invalid lengthToCross value! lengthToCross was set in: " + (GARun.bitsInDouble / 2));
			this.lengthToCross = (GARun.bitsInDouble) / 2;
		} else {
			this.lengthToCross = lenghtToCross;
		}
		Random r = new Random(System.currentTimeMillis());
		this.crosspoint = r.nextInt(GARun.bitsInDouble);
	}
	
	public Anular () {
		this((GARun.bitsInDouble) / 2);
	}
	
	@Override
	public Collection<Individual> method(Collection<Individual> individuals) {
		if (individuals.size() != 2) {
			return null;
		}
		List<Individual> listIndividuals = new LinkedList<Individual>(individuals);
		Long firstMask = buildMask ();
		Long sndmask = ~firstMask;
		Long firstIndividual = Double.doubleToRawLongBits(listIndividuals.get(0).getIndividualValue());
		Long sndIndividual = Double.doubleToRawLongBits(listIndividuals.get(1).getIndividualValue());
		Long newFirstIndividual = (sndIndividual & firstMask) | (firstIndividual & sndmask);
		Long newSndIndividual = (firstIndividual & firstMask) | (sndIndividual & sndmask);
		Individual newFIndividual = new Individual(Double.longBitsToDouble(newFirstIndividual));
		Individual newSIndividual = new Individual(Double.longBitsToDouble(newSndIndividual));
		Collection<Individual> newListIndividuals = new LinkedList<Individual>();
		newListIndividuals.add(newFIndividual);
		newListIndividuals.add(newSIndividual);
		return newListIndividuals;
	}

	private Long buildMask() {
		Long mask = 0x0000000000000000L;
		Long auxMask = 0x0000000000000001L << this.crosspoint;
		for (int i = 0; i < this.lengthToCross; i++) {
			mask |= auxMask;
			auxMask <<= 1;
			if (auxMask == 0) {
				auxMask = 0x0000000000000001L;
			}
		}
		return mask;
	}

}
